"""
 @desc: 用来存放修改过的 Airtest 代码
"""
import json
import logging
import os
import shutil
import uuid
from airtest.cli.info import get_script_info
from airtest.core.api import connect_device
from airtest.core.helper import G, log
from airtest.core.settings import Settings as ST
from airtest.report.report import LogToHtml
from airtest.utils.compat import script_dir_name

from Base.BaseSettings import LogsDIR, ReportDIR, ServeReportDIR, AirtestResourceDIR, EntranceDIR, ServePath

logger = logging.getLogger('airtest')
logger.setLevel(logging.INFO)


def only_auto_setup(basedir=None, devices=None, project_root=None, compress=None):
    """
    单纯的建立设备连接
    Auto setup running env and try connect android device if not device connected.

    :param basedir: basedir of script, __file__ is also acceptable.
    :param devices: connect_device uri in list.
    :param logdir: log dir for script report, default is None for no log, set to ``True`` for ``<basedir>/log``.
    :param project_root: project root dir for `using` api.
    :param compress: The compression rate of the screenshot image, integer in range [1, 99], default is 10
    :Example:
        >>> auto_setup(__file__)
        >>> auto_setup(__file__, devices=["Android://127.0.0.1:5037/SJE5T17B17"],
        ...             logdir=True, project_root=r"D:\\test\\logs", compress=90)
    """
    if basedir:
        if os.path.isfile(basedir):
            basedir = os.path.dirname(basedir)
        if basedir not in G.BASEDIR:
            G.BASEDIR.append(basedir)
    if devices:
        for dev in devices:
            connect_device(dev)
    if project_root:
        ST.PROJECT_ROOT = project_root
    if compress:
        ST.SNAPSHOT_QUALITY = compress


def only_auto_logdir(logdir):
    if os.path.exists(logdir):
        shutil.rmtree(logdir)
    os.makedirs(logdir, exist_ok=True)
    ST.LOG_DIR = logdir
    G.LOGGER.set_logfile(os.path.join(ST.LOG_DIR, ST.LOG_FILE))


def uuid_report(case_desc, title='', author=''):
    """
    三次闭包装饰器 - 生成随机的报告地址
    :param case_desc: 用例名称
    :return:
    """
    case_info = {
        "title": title,
        "author": author,
        "desc": case_desc
    }

    def outer(func):
        def inner(self, *args, **kwargs):
            log_name = uuid.uuid4()
            only_auto_logdir(f"{LogsDIR}{log_name}")
            try:
                f = func(self, *args, **kwargs)
            except Exception as e:
                log(e, snapshot=True)
                raise e
            finally:
                # 生成报告
                # 判断当前的ReportDir目录是否存在，不存在则创建
                html_report = fr"{ReportDIR}{log_name}.html"
                if not os.path.exists(os.path.dirname(html_report)):
                    # 如果不存在则创建目录
                    print("目录不存在，则新建目录：", os.path.dirname(html_report))
                    os.makedirs(os.path.dirname(html_report))
                diy_simple_report(__file__, logpath=f"{LogsDIR}{log_name}", output=html_report, case_info=case_info)
                # html 测试报告的路径
                self.__dict__['_htmlPath'] = ServeReportDIR + os.path.basename(html_report)
                # case 的描述信息
                self.__dict__['_testMethodDoc'] = case_desc
            return f

        return inner

    return outer


def diy_simple_report(filepath, logpath=True, logfile=None, output="log.html", case_info={}):
    path, name = script_dir_name(filepath)
    if logpath is True:
        logpath = os.path.join(path, getattr(ST, "LOG_DIR", "log"))
    rpt = DIYLogToHtml(path, logpath, logfile=logfile or getattr(ST, "LOG_FILE", "log.txt"), script_name=name)
    rpt.report("log_template.html", output_file=output, case_info=case_info)


class DIYLogToHtml(LogToHtml):
    def __init__(self, script_root, log_root="", static_root="", export_dir=None, script_name="", logfile=None,
                 lang="en", plugins=None):
        self.log = []
        self.devices = {}
        self.script_root = script_root
        self.script_name = script_name
        if not self.script_name or os.path.isfile(self.script_root):
            self.script_root, self.script_name = script_dir_name(self.script_root)
        self.log_root = log_root or ST.LOG_DIR or os.path.join(".", "log")
        self.static_root = static_root or AirtestResourceDIR
        self.test_result = True
        self.run_start = None
        self.run_end = None
        self.export_dir = export_dir
        self.logfile = logfile or getattr(ST, "LOG_FILE", "log.txt")
        self.lang = lang
        self.init_plugin_modules(plugins)

    def report_data(self, output_file=None, record_list=None, case_info={}):
        """
        Generate data for the report page

        :param output_file: The file name or full path of the output file, default HTML_FILE
        :param record_list: List of screen recording files
        :return:
        """
        self._load()
        steps = self._analyse()

        script_path = os.path.join(self.script_root, self.script_name)
        info = json.loads(get_script_info(script_path))
        info['devices'] = self.devices
        info['title'] = case_info.get("title", "")
        info['author'] = case_info.get("author", "")
        info['desc'] = case_info.get("desc", "")

        if record_list:
            records = [os.path.join("log", f) if self.export_dir
                       else os.path.abspath(os.path.join(self.log_root, f)) for f in record_list]
        else:
            records = []

        if not self.static_root.endswith(os.path.sep):
            self.static_root = self.static_root.replace("\\", "/")
            self.static_root += "/"

        if not output_file:
            output_file = "log.html"

        data = {}
        data['steps'] = steps
        data['name'] = self.script_root
        data['scale'] = self.scale
        data['test_result'] = self.test_result
        data['run_end'] = self.run_end
        data['run_start'] = self.run_start
        data['static_root'] = self.static_root
        data['lang'] = self.lang
        data['records'] = records
        data['info'] = info
        data['log'] = self.get_relative_log(output_file)
        data['console'] = self.get_console(output_file)
        # 如果带有<>符号，容易被highlight.js认为是特殊语法，有可能导致页面显示异常，尝试替换成不常用的{}
        info = json.dumps(data).replace("<", "{").replace(">", "}")
        # 替换为服务器的路径
        info = info.replace(EntranceDIR.replace("\\", "\\\\"), ServePath)
        data['data'] = info
        return data

    def report(self, template_name="log_template.html", output_file="log.html", record_list=None, case_info={}):
        """
        Generate the report page, you can add custom data and overload it if needed

        :param template_name: default is HTML_TPL
        :param output_file: The file name or full path of the output file, default HTML_FILE
        :param record_list: List of screen recording files
        :return:
        """
        if not self.script_name:
            path, self.script_name = script_dir_name(self.script_root)

        if self.export_dir:
            self.script_root, self.log_root = self._make_export_dir()
            # output_file可传入文件名，或绝对路径
            output_file = output_file if output_file and os.path.isabs(output_file) \
                else os.path.join(self.script_root, output_file or "log.html")
            if not self.static_root.startswith("http"):
                self.static_root = "static/"

        if not record_list:
            record_list = [f for f in os.listdir(self.log_root) if f.endswith(".mp4")]
        data = self.report_data(output_file=output_file, record_list=record_list, case_info=case_info)
        return self._render(template_name, output_file, **data)
